const std = @import("std");
const uart = @import("uart.zig");
pub const print = uart.print;

const page = @import("page.zig");

const STACK_SIZE = 1024 * 16;
export var stack0: [STACK_SIZE]u8 align(16) = undefined;

const start_code = std.fmt.comptimePrint(
    \\  csrr    t0, mhartid
    \\  beqz    t0, hart_0
    \\
    \\park:
    \\  wfi
    \\  j       park
    \\
    \\hart_0:
    \\  # Setup stacks, the stack grows from bottom to top, so we put the
    \\  # stack pointer to the very end of the stack range.
    \\  la      sp, stack0 + {}     # set the initial stack pointer
    \\                              # to the end of the first stack space
    \\  j       kmain               # hart 0 jump to kmain function
, .{STACK_SIZE});

export fn _start() linksection(".os_start") callconv(.naked) noreturn {
    asm volatile (start_code);
}

export fn kmain() noreturn {
    uart.init();
    page.init();

    main() catch |e| @panic(@errorName(e));

    print("-------------- end.. ---------------\n", .{});
    while (true) {} // stop here!
}

fn main() !void {
    print("Hello, RVOS!\n", .{});

    page.info();

    var frame0 = async task0();
    var frame1 = async task1();

    var i: u1 = 0;
    while (true) : (i +%= 1) {
        if (i == 0) {
            resume frame0;
        } else {
            resume frame1;
        }
    }
}

fn task0() void {
    print("Task 0: Created!\n", .{});
    suspend {}

    while (true) {
        print("Task 0: Running...\n", .{});
        delay();
        suspend {}
    }
}

fn task1() void {
    print("Task 1: Created!\n", .{});
    suspend {}

    while (true) {
        print("Task 1: Running...\n", .{});
        delay();
        suspend {}
    }
}

fn delay() void {
    var i: usize = 5000 * 5000;
    const ptr: *volatile usize = &i;
    while (ptr.* > 0) {
        ptr.* -= 1;
    }
}

pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
    @branchHint(.cold);
    print("KERNEL PANIC: {s}\n", .{msg});
    while (true) {}
}
